package cn.tm.ms.nerver.neural;

import java.util.concurrent.atomic.AtomicInteger;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.netflix.hystrix.HystrixCommand;

import cn.tm.ms.nerver.common.SystemClock;
import cn.tm.ms.nerver.neural.entry.NeuralConf;
import cn.tm.ms.nerver.neural.route.IRoute;

/**
 * 神经元
 * 
 * @author lry
 *
 * @param <REQ> 请求对象
 * @param <RES> 响应对象
 */
public class Neural<REQ, RES> extends HystrixCommand<RES> {

	private static final Logger logger=LogManager.getLogger(Neural.class);
	
	private REQ req;
	private NeuralConf conf;
	private IRoute<REQ, RES> route;
	private AtomicInteger retryTimes = new AtomicInteger();// 重试计数器

	public Neural(Setter setter, NeuralConf conf, IRoute<REQ, RES> route, REQ req) {
		super(setter);
		this.req = req;
		this.conf = conf;
		this.route = route;
	}

	/**
	 * 依赖模块
	 */
	protected RES run() {
		try {
			return route.route(req);
		} catch (Throwable t) {
			logger.error("Run route is failure, error is ["+t.getMessage()+"]",t);
			t.printStackTrace();
			if (conf.getMaxRetryNum() > 0 || conf.getMaxRetryNum() == -1) {// 进入容错重试,-1表示无限重试
				throw new RuntimeException();
			} else {
				if (conf.isMockEnable()) {// 检查mock开关
					try {
						if(logger.isInfoEnabled()){
							logger.info("Run mockEnable is open, please waitting.. ");
						}
						return route.mock(req);// 调用mock服务进行返回
					} catch (Throwable e) {
						logger.error("Run mock is failure, error is ["+e.getMessage()+"]",e);
						e.printStackTrace();
					}
				}
			}
		}
		return null;
	}

	/**
	 * 容错
	 */
	protected RES getFallback() {
		int retryFTNum = 0;// 已经重试容错次数
		while (retryFTNum < conf.getMaxRetryNum() || conf.getMaxRetryNum() == -1) {// 循环进入容错重试流
			retryFTNum++;
			try {
				int times = retryTimes.addAndGet(1);// 容错执行次数
				if(logger.isInfoEnabled()){
					logger.info("Is fallback route retry "+times+" times, please waitting.. ");
				}
				long sleepTime = route.breathCycle(times, conf.getMaxRetryNum(), conf.getRetryCycle(), SystemClock.now());// 计算本次容错休眠时间
				if (sleepTime > 0) {
					Thread.sleep(sleepTime);
				}

				return route.route(req);
			} catch (Throwable t) {
				logger.error("Fallback route is failure, error is ["+t.getMessage()+"]",t);
				t.printStackTrace();
				if (conf.getMaxRetryNum() == -1) {// 进入无限循环状态
					continue;
				} else if (retryFTNum >= conf.getMaxRetryNum()) {// 重试完毕,则该退出了
					if(logger.isInfoEnabled()){
						logger.info("Fallback route retry already finished.");
					}
					if (conf.isMockEnable()) {// 检查mock开关
						try {
							if(logger.isInfoEnabled()){
								logger.info("Fallback mockEnable is open, please waitting.. ");
							}
							return route.mock(req);// 调用mock服务进行返回
						} catch (Throwable e) {
							logger.error("Fallback mock is failure, error is ["+e.getMessage()+"]",e);
							e.printStackTrace();
						}
					} else {
						if(logger.isInfoEnabled()){
							logger.info("Fallback mockEnable is close.");
						}
						if (conf.isFallbackFEEnable()) {// 所有容错失败后交易是否需要向外抛异常
							throw new RuntimeException(t);
						}
					}
					break;
				}
			}
		}
		return null;
	}

}
